<!DOCTYPE HTML>
<!--
	Dimension by HTML5 UP
	html5up.net | @ajlkn
	Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
 <head>
  <title>
   Dimension by HTML5 UP
  </title>
  <!-- <meta charset="utf-8" /> -->
  <!-- <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> -->
  <meta charset="utf-8"/>
  <meta content="width=device-width,initial-scale=1.0" name="viewport"/>
  <link href="../../assets/css/article.css" rel="stylesheet"/>
  <link href="https://cdn.bootcss.com/highlight.js/9.15.8/styles/github.min.css" rel="stylesheet"/>
  <noscript>
   <link href="../../assets/css/noscript.css" rel="stylesheet"/>
  </noscript>
 </head>
 <body>
  <div id="app">
  </div>
  <!-- built files will be auto injected -->
 </body>
 <body class="is-preload">
  <!-- Wrapper -->
  <div id="wrapper">
   <!-- Main -->
   <div id="main">
    <article id="article">
     <h1 id="soulsouldubboclient">
      Soul网关源码解析（二十四）SoulDubboClient注解
     </h1>
     <hr/>
     <h2 id="_1">
      简介
     </h2>
     <p>
      本篇文章来探索下Soul网关Apache Dubbo客户端的注册处理流程
     </p>
     <h2 id="_2">
      概览
     </h2>
     <p>
      有了上一篇的基础：
      <a href="https://juejin.cn/post/6922643958455599111">
       Soul网关源码解析（二十三）SoulSpringMvcClient注解
      </a>
     </p>
     <p>
      我们直接在Soul-Client模块下定位到：soul-client-apache-dubbo，找到进行具体处理的类：ApacheDubboServiceBeanPostProcessor
     </p>
     <p>
      我们看下是如何获取到Bean的？如果判断是Soul-Client-Apache-Dubbo的？注册了那些信息？
     </p>
     <p>
      下面开始分析：
     </p>
     <h2 id="debug">
      源码Debug
     </h2>
     <h3 id="bean">
      如何获取到Bean
     </h3>
     <p>
      直接定位到处理类如下，onApplicationEvent方法是入口，那应该是从这里开始像HTTP那样获取Bean的
     </p>
     <p>
      首先看下继承的类，可以看到和HTTP不同，这里是：ApplicationListener
      <contextrefreshedevent>
      </contextrefreshedevent>
     </p>
     <p>
      由于不熟悉，我们搜索下它是干嘛的，参考链接是：
      <a href="https://www.jianshu.com/p/4bd3f68cb179">
       ApplicationListener和ContextRefreshedEvent
      </a>
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="err">在</span><span class="n">IOC的容器的启动过程</span><span class="err">，当所有的</span><span class="n">bean都已经处理完成之后</span><span class="err">，</span><span class="n">spring</span> <span class="n">ioc容器会有一个发布事件的动作</span><span class="err">。从</span> <span class="n">AbstractApplicationContext</span> <span class="err">的源码中就可以看出</span>
<span class="err">当</span><span class="n">ioc容器加载处理完相应的bean之后</span><span class="err">，也给我们提供了一个机会（先有</span><span class="n">InitializingBean</span><span class="err">，后有</span><span class="n">ApplicationListener</span><span class="o">&lt;</span><span class="n">ContextRefreshedEvent</span><span class="o">&gt;</span><span class="err">），可以去做一些自己想做的事。其实这也就是</span><span class="n">spring</span> <span class="n">ioc容器给提供的一个扩展的地方</span><span class="err">。我们可以这样使用这个扩展机制。</span>

<span class="err">作者：</span><span class="n">AmeeLove</span>
<span class="err">链接：</span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">www</span><span class="p">.</span><span class="n">jianshu</span><span class="p">.</span><span class="n">com</span><span class="o">/</span><span class="n">p</span><span class="o">/</span><span class="mi">4</span><span class="n">bd3f68cb179</span>
<span class="err">来源：简书</span>
<span class="err">著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。</span>
</code></pre>
     </div>
     <p>
      大致就是在所有容器都初始化完成以后，会触发执行
     </p>
     <p>
      我们在下面的代码中打断点进行调试，发现:contextRefreshedEvent.getApplicationContext().getBeansOfType(ServiceBean.class),执行完以后就可以得到我们示例中的两个Impl服务，感觉挺便利的。这个感觉需要对Dubbo有一些熟悉，现在又学到了一手
     </p>
     <p>
      获取以后遍历开启线程去进行注册，获取Bean的过程大致就是这样了
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ApacheDubboServiceBeanPostProcessor</span> <span class="kd">implements</span> <span class="n">ApplicationListener</span><span class="o">&lt;</span><span class="n">ContextRefreshedEvent</span><span class="o">&gt;</span> <span class="p">{</span>

    <span class="c1">// DubboConfig(adminUrl=http://localhost:9095, contextPath=/dubbo, appName=dubbo)</span>
    <span class="kd">private</span> <span class="n">DubboConfig</span> <span class="n">dubboConfig</span><span class="p">;</span>

    <span class="kd">private</span> <span class="n">ExecutorService</span> <span class="n">executorService</span><span class="p">;</span>

    <span class="c1">// http://localhost:9095/soul-client/dubbo-register</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">url</span><span class="p">;</span>

    <span class="kd">public</span> <span class="nf">ApacheDubboServiceBeanPostProcessor</span><span class="p">(</span><span class="kd">final</span> <span class="n">DubboConfig</span> <span class="n">dubboConfig</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">contextPath</span> <span class="o">=</span> <span class="n">dubboConfig</span><span class="p">.</span><span class="na">getContextPath</span><span class="p">();</span>
        <span class="n">String</span> <span class="n">adminUrl</span> <span class="o">=</span> <span class="n">dubboConfig</span><span class="p">.</span><span class="na">getAdminUrl</span><span class="p">();</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">StringUtils</span><span class="p">.</span><span class="na">isEmpty</span><span class="p">(</span><span class="n">contextPath</span><span class="p">)</span>
                <span class="o">||</span> <span class="n">StringUtils</span><span class="p">.</span><span class="na">isEmpty</span><span class="p">(</span><span class="n">adminUrl</span><span class="p">))</span> <span class="p">{</span>
            <span class="k">throw</span> <span class="k">new</span> <span class="n">RuntimeException</span><span class="p">(</span><span class="s">"apache dubbo client must config the contextPath, adminUrl"</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="k">this</span><span class="p">.</span><span class="na">dubboConfig</span> <span class="o">=</span> <span class="n">dubboConfig</span><span class="p">;</span>
        <span class="n">url</span> <span class="o">=</span> <span class="n">dubboConfig</span><span class="p">.</span><span class="na">getAdminUrl</span><span class="p">()</span> <span class="o">+</span> <span class="s">"/soul-client/dubbo-register"</span><span class="p">;</span>
        <span class="n">executorService</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ThreadPoolExecutor</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="n">L</span><span class="p">,</span> <span class="n">TimeUnit</span><span class="p">.</span><span class="na">MILLISECONDS</span><span class="p">,</span> <span class="k">new</span> <span class="n">LinkedBlockingQueue</span><span class="o">&lt;&gt;</span><span class="p">());</span>
    <span class="p">}</span>

    <span class="nd">@Override</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">onApplicationEvent</span><span class="p">(</span><span class="kd">final</span> <span class="n">ContextRefreshedEvent</span> <span class="n">contextRefreshedEvent</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">nonNull</span><span class="p">(</span><span class="n">contextRefreshedEvent</span><span class="p">.</span><span class="na">getApplicationContext</span><span class="p">().</span><span class="na">getParent</span><span class="p">()))</span> <span class="p">{</span>
            <span class="k">return</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="c1">// Fix bug(https://github.com/dromara/soul/issues/415), upload dubbo metadata on ContextRefreshedEvent</span>
        <span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span> <span class="n">ServiceBean</span><span class="o">&gt;</span> <span class="n">serviceBean</span> <span class="o">=</span> <span class="n">contextRefreshedEvent</span><span class="p">.</span><span class="na">getApplicationContext</span><span class="p">().</span><span class="na">getBeansOfType</span><span class="p">(</span><span class="n">ServiceBean</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">Map</span><span class="p">.</span><span class="na">Entry</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span> <span class="n">ServiceBean</span><span class="o">&gt;</span> <span class="n">entry</span> <span class="p">:</span> <span class="n">serviceBean</span><span class="p">.</span><span class="na">entrySet</span><span class="p">())</span> <span class="p">{</span>
            <span class="n">executorService</span><span class="p">.</span><span class="na">execute</span><span class="p">(()</span> <span class="o">-&gt;</span> <span class="n">handler</span><span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="na">getValue</span><span class="p">()));</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <h3 id="_3">
      判断是否需要注册
     </h3>
     <p>
      我们直接来到具体处理的handler函数
     </p>
     <p>
      可以看到其直接从bean获取到类信息，而且如果是发射代理类的话，要获取到原来被代理的类（这里有些奇怪，为啥不能直接使用代理类，是方法生成后有什么不同吗？后面去探索一下）
     </p>
     <p>
      这里没有看到像HTTP那样的通配符了，Dubbo好像不能这样，这个感觉是个值得注意的点，感觉通配的话在从URL转Dubbo的路径的时候不好转，所有没有提供这方面的机制
     </p>
     <p>
      最后遍历类中的所有方法，如果有SoulDubboClient注解，将其接口注入到Admin中
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ApacheDubboServiceBeanPostProcessor</span> <span class="kd">implements</span> <span class="n">ApplicationListener</span><span class="o">&lt;</span><span class="n">ContextRefreshedEvent</span><span class="o">&gt;</span> <span class="p">{</span>

    <span class="kd">private</span> <span class="kt">void</span> <span class="nf">handler</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServiceBean</span> <span class="n">serviceBean</span><span class="p">)</span> <span class="p">{</span>
        <span class="c1">// clazz == org.dromara.soul.examples.apache.dubbo.service.impl.DubboTestServiceImpl</span>
        <span class="n">Class</span><span class="o">&lt;?&gt;</span> <span class="n">clazz</span> <span class="o">=</span> <span class="n">serviceBean</span><span class="p">.</span><span class="na">getRef</span><span class="p">().</span><span class="na">getClass</span><span class="p">();</span>
        <span class="c1">// 这应该是得到反射代理生成的原本的类吧（为啥不能直接使用代理类呢？）</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">ClassUtils</span><span class="p">.</span><span class="na">isCglibProxyClass</span><span class="p">(</span><span class="n">clazz</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">String</span> <span class="n">superClassName</span> <span class="o">=</span> <span class="n">clazz</span><span class="p">.</span><span class="na">getGenericSuperclass</span><span class="p">().</span><span class="na">getTypeName</span><span class="p">();</span>
            <span class="k">try</span> <span class="p">{</span>
                <span class="n">clazz</span> <span class="o">=</span> <span class="n">Class</span><span class="p">.</span><span class="na">forName</span><span class="p">(</span><span class="n">superClassName</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">ClassNotFoundException</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">log</span><span class="p">.</span><span class="na">error</span><span class="p">(</span><span class="n">String</span><span class="p">.</span><span class="na">format</span><span class="p">(</span><span class="s">"class not found: %s"</span><span class="p">,</span> <span class="n">superClassName</span><span class="p">));</span>
                <span class="k">return</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="c1">// 遍历所有的方法，如果有相关的注解，则注册到Admin中</span>
        <span class="kd">final</span> <span class="n">Method</span><span class="o">[]</span> <span class="n">methods</span> <span class="o">=</span> <span class="n">ReflectionUtils</span><span class="p">.</span><span class="na">getUniqueDeclaredMethods</span><span class="p">(</span><span class="n">clazz</span><span class="p">);</span>
        <span class="k">for</span> <span class="p">(</span><span class="n">Method</span> <span class="n">method</span> <span class="p">:</span> <span class="n">methods</span><span class="p">)</span> <span class="p">{</span>
            <span class="c1">// public org.dromara.soul.examples.dubbo.api.entity.DubboTest org.dromara.soul.examples.apache.dubbo.service.impl.DubboTestServiceImpl.insert(org.dromara.soul.examples.dubbo.api.entity.DubboTest)</span>
            <span class="n">SoulDubboClient</span> <span class="n">soulDubboClient</span> <span class="o">=</span> <span class="n">method</span><span class="p">.</span><span class="na">getAnnotation</span><span class="p">(</span><span class="n">SoulDubboClient</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">nonNull</span><span class="p">(</span><span class="n">soulDubboClient</span><span class="p">))</span> <span class="p">{</span>
                <span class="n">RegisterUtils</span><span class="p">.</span><span class="na">doRegister</span><span class="p">(</span><span class="n">buildJsonParams</span><span class="p">(</span><span class="n">serviceBean</span><span class="p">,</span> <span class="n">soulDubboClient</span><span class="p">,</span> <span class="n">method</span><span class="p">),</span> <span class="n">url</span><span class="p">,</span> <span class="n">RpcTypeEnum</span><span class="p">.</span><span class="na">DUBBO</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <h3 id="_4">
      注册信息
     </h3>
     <p>
      下面是构造请求相关的函数，从其中可以看出，注册了选择器和规则相关的信息。在其中的Ext中还有分组、版本、负载均衡等信息
     </p>
     <p>
      我们没有看到像HTTP的那些IP和端口之类的信息，但联想到RPC的相关知识，大致知道Dubbo已经将其注册到Zookeeper中了
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ApacheDubboServiceBeanPostProcessor</span> <span class="kd">implements</span> <span class="n">ApplicationListener</span><span class="o">&lt;</span><span class="n">ContextRefreshedEvent</span><span class="o">&gt;</span> <span class="p">{</span>

    <span class="c1">// DubboConfig(adminUrl=http://localhost:9095, contextPath=/dubbo, appName=dubbo)</span>
    <span class="kd">private</span> <span class="n">DubboConfig</span> <span class="n">dubboConfig</span><span class="p">;</span>

    <span class="kd">private</span> <span class="n">ExecutorService</span> <span class="n">executorService</span><span class="p">;</span>

    <span class="c1">// http://localhost:9095/soul-client/dubbo-register</span>
    <span class="kd">private</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">url</span><span class="p">;</span>

    <span class="kd">private</span> <span class="n">String</span> <span class="nf">buildJsonParams</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServiceBean</span> <span class="n">serviceBean</span><span class="p">,</span> <span class="kd">final</span> <span class="n">SoulDubboClient</span> <span class="n">soulDubboClient</span><span class="p">,</span> <span class="kd">final</span> <span class="n">Method</span> <span class="n">method</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">String</span> <span class="n">appName</span> <span class="o">=</span> <span class="n">dubboConfig</span><span class="p">.</span><span class="na">getAppName</span><span class="p">();</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">StringUtils</span><span class="p">.</span><span class="na">isEmpty</span><span class="p">(</span><span class="n">appName</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">appName</span> <span class="o">=</span> <span class="n">serviceBean</span><span class="p">.</span><span class="na">getApplication</span><span class="p">().</span><span class="na">getName</span><span class="p">();</span>
        <span class="p">}</span>
        <span class="n">String</span> <span class="n">path</span> <span class="o">=</span> <span class="n">dubboConfig</span><span class="p">.</span><span class="na">getContextPath</span><span class="p">()</span> <span class="o">+</span> <span class="n">soulDubboClient</span><span class="p">.</span><span class="na">path</span><span class="p">();</span>
        <span class="n">String</span> <span class="n">desc</span> <span class="o">=</span> <span class="n">soulDubboClient</span><span class="p">.</span><span class="na">desc</span><span class="p">();</span>
        <span class="c1">// org.dromara.soul.examples.dubbo.api.service.DubboTestService</span>
        <span class="n">String</span> <span class="n">serviceName</span> <span class="o">=</span> <span class="n">serviceBean</span><span class="p">.</span><span class="na">getInterface</span><span class="p">();</span>
        <span class="n">String</span> <span class="n">configRuleName</span> <span class="o">=</span> <span class="n">soulDubboClient</span><span class="p">.</span><span class="na">ruleName</span><span class="p">();</span>
        <span class="c1">// /dubbo/findAll</span>
        <span class="n">String</span> <span class="n">ruleName</span> <span class="o">=</span> <span class="p">(</span><span class="s">""</span><span class="p">.</span><span class="na">equals</span><span class="p">(</span><span class="n">configRuleName</span><span class="p">))</span> <span class="o">?</span> <span class="n">path</span> <span class="p">:</span> <span class="n">configRuleName</span><span class="p">;</span>
        <span class="n">String</span> <span class="n">methodName</span> <span class="o">=</span> <span class="n">method</span><span class="p">.</span><span class="na">getName</span><span class="p">();</span>
        <span class="n">Class</span><span class="o">&lt;?&gt;[]</span> <span class="n">parameterTypesClazz</span> <span class="o">=</span> <span class="n">method</span><span class="p">.</span><span class="na">getParameterTypes</span><span class="p">();</span>
        <span class="n">String</span> <span class="n">parameterTypes</span> <span class="o">=</span> <span class="n">Arrays</span><span class="p">.</span><span class="na">stream</span><span class="p">(</span><span class="n">parameterTypesClazz</span><span class="p">).</span><span class="na">map</span><span class="p">(</span><span class="n">Class</span><span class="p">::</span><span class="n">getName</span><span class="p">)</span>
                <span class="p">.</span><span class="na">collect</span><span class="p">(</span><span class="n">Collectors</span><span class="p">.</span><span class="na">joining</span><span class="p">(</span><span class="s">","</span><span class="p">));</span>
        <span class="n">MetaDataDTO</span> <span class="n">metaDataDTO</span> <span class="o">=</span> <span class="n">MetaDataDTO</span><span class="p">.</span><span class="na">builder</span><span class="p">()</span>
                <span class="p">.</span><span class="na">appName</span><span class="p">(</span><span class="n">appName</span><span class="p">)</span>
                <span class="p">.</span><span class="na">serviceName</span><span class="p">(</span><span class="n">serviceName</span><span class="p">)</span>
                <span class="p">.</span><span class="na">methodName</span><span class="p">(</span><span class="n">methodName</span><span class="p">)</span>
                <span class="p">.</span><span class="na">contextPath</span><span class="p">(</span><span class="n">dubboConfig</span><span class="p">.</span><span class="na">getContextPath</span><span class="p">())</span>
                <span class="p">.</span><span class="na">path</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
                <span class="p">.</span><span class="na">ruleName</span><span class="p">(</span><span class="n">ruleName</span><span class="p">)</span>
                <span class="p">.</span><span class="na">pathDesc</span><span class="p">(</span><span class="n">desc</span><span class="p">)</span>
                <span class="p">.</span><span class="na">parameterTypes</span><span class="p">(</span><span class="n">parameterTypes</span><span class="p">)</span>
                <span class="p">.</span><span class="na">rpcExt</span><span class="p">(</span><span class="n">buildRpcExt</span><span class="p">(</span><span class="n">serviceBean</span><span class="p">))</span>
                <span class="p">.</span><span class="na">rpcType</span><span class="p">(</span><span class="s">"dubbo"</span><span class="p">)</span>
                <span class="p">.</span><span class="na">enabled</span><span class="p">(</span><span class="n">soulDubboClient</span><span class="p">.</span><span class="na">enabled</span><span class="p">())</span>
                <span class="p">.</span><span class="na">build</span><span class="p">();</span>
        <span class="k">return</span> <span class="n">OkHttpTools</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">getGson</span><span class="p">().</span><span class="na">toJson</span><span class="p">(</span><span class="n">metaDataDTO</span><span class="p">);</span>

    <span class="p">}</span>

    <span class="kd">private</span> <span class="n">String</span> <span class="nf">buildRpcExt</span><span class="p">(</span><span class="kd">final</span> <span class="n">ServiceBean</span> <span class="n">serviceBean</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">MetaDataDTO</span><span class="p">.</span><span class="na">RpcExt</span> <span class="n">build</span> <span class="o">=</span> <span class="n">MetaDataDTO</span><span class="p">.</span><span class="na">RpcExt</span><span class="p">.</span><span class="na">builder</span><span class="p">()</span>
                <span class="p">.</span><span class="na">group</span><span class="p">(</span><span class="n">StringUtils</span><span class="p">.</span><span class="na">isNotEmpty</span><span class="p">(</span><span class="n">serviceBean</span><span class="p">.</span><span class="na">getGroup</span><span class="p">())</span> <span class="o">?</span> <span class="n">serviceBean</span><span class="p">.</span><span class="na">getGroup</span><span class="p">()</span> <span class="p">:</span> <span class="s">""</span><span class="p">)</span>
                <span class="p">.</span><span class="na">version</span><span class="p">(</span><span class="n">StringUtils</span><span class="p">.</span><span class="na">isNotEmpty</span><span class="p">(</span><span class="n">serviceBean</span><span class="p">.</span><span class="na">getVersion</span><span class="p">())</span> <span class="o">?</span> <span class="n">serviceBean</span><span class="p">.</span><span class="na">getVersion</span><span class="p">()</span> <span class="p">:</span> <span class="s">""</span><span class="p">)</span>
                <span class="p">.</span><span class="na">loadbalance</span><span class="p">(</span><span class="n">StringUtils</span><span class="p">.</span><span class="na">isNotEmpty</span><span class="p">(</span><span class="n">serviceBean</span><span class="p">.</span><span class="na">getLoadbalance</span><span class="p">())</span> <span class="o">?</span> <span class="n">serviceBean</span><span class="p">.</span><span class="na">getLoadbalance</span><span class="p">()</span> <span class="p">:</span> <span class="n">Constants</span><span class="p">.</span><span class="na">DEFAULT_LOADBALANCE</span><span class="p">)</span>
                <span class="p">.</span><span class="na">retries</span><span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">isNull</span><span class="p">(</span><span class="n">serviceBean</span><span class="p">.</span><span class="na">getRetries</span><span class="p">())</span> <span class="o">?</span> <span class="n">Constants</span><span class="p">.</span><span class="na">DEFAULT_RETRIES</span> <span class="p">:</span> <span class="n">serviceBean</span><span class="p">.</span><span class="na">getRetries</span><span class="p">())</span>
                <span class="p">.</span><span class="na">timeout</span><span class="p">(</span><span class="n">Objects</span><span class="p">.</span><span class="na">isNull</span><span class="p">(</span><span class="n">serviceBean</span><span class="p">.</span><span class="na">getTimeout</span><span class="p">())</span> <span class="o">?</span> <span class="n">Constants</span><span class="p">.</span><span class="na">DEFAULT_CONNECT_TIMEOUT</span> <span class="p">:</span> <span class="n">serviceBean</span><span class="p">.</span><span class="na">getTimeout</span><span class="p">())</span>
                <span class="p">.</span><span class="na">url</span><span class="p">(</span><span class="s">""</span><span class="p">)</span>
                <span class="p">.</span><span class="na">build</span><span class="p">();</span>
        <span class="k">return</span> <span class="n">OkHttpTools</span><span class="p">.</span><span class="na">getInstance</span><span class="p">().</span><span class="na">getGson</span><span class="p">().</span><span class="na">toJson</span><span class="p">(</span><span class="n">build</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <h3 id="apache-dubbo">
      Apache Dubbo 注册调用梳理
     </h3>
     <p>
      下面是最终发送的请求信息，不像HTTP那样直观，如果没有接触过RPC，可以感觉有点懵，这里梳理一下RPC相关的注册调用流程
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="p">{</span>
    <span class="nt">"appName"</span><span class="p">:</span> <span class="s2">"dubbo"</span><span class="p">,</span>
    <span class="nt">"contextPath"</span><span class="p">:</span> <span class="s2">"/dubbo"</span><span class="p">,</span>
    <span class="nt">"path"</span><span class="p">:</span> <span class="s2">"/dubbo/insert"</span><span class="p">,</span>
    <span class="nt">"pathDesc"</span><span class="p">:</span> <span class="s2">"Insert a row of data"</span><span class="p">,</span>
    <span class="nt">"rpcType"</span><span class="p">:</span> <span class="s2">"dubbo"</span><span class="p">,</span>
    <span class="nt">"serviceName"</span><span class="p">:</span> <span class="s2">"org.dromara.soul.examples.dubbo.api.service.DubboTestService"</span><span class="p">,</span>
    <span class="nt">"methodName"</span><span class="p">:</span> <span class="s2">"insert"</span><span class="p">,</span>
    <span class="nt">"ruleName"</span><span class="p">:</span> <span class="s2">"/dubbo/insert"</span><span class="p">,</span>
    <span class="nt">"parameterTypes"</span><span class="p">:</span> <span class="s2">"org.dromara.soul.examples.dubbo.api.entity.DubboTest"</span><span class="p">,</span>
    <span class="nt">"rpcExt"</span><span class="p">:</span> <span class="s2">"{\"group\":\"\",\"version\":\"\",\"loadbalance\":\"random\",\"retries\":2,\"timeout\":10000,\"url\":\"\"}"</span><span class="p">,</span>
    <span class="nt">"enabled"</span><span class="p">:</span> <span class="kc">true</span>
<span class="p">}</span>
</code></pre>
     </div>
     <p>
      一个Dubbo的注册和调用流程图如下：
     </p>
     <p>
      <img alt="" src="./picture/soul-dubbo.png"/>
     </p>
     <p>
      注册和调用都有可能同时发生，也就是路由Soul网关的路由时可以动态变化的
     </p>
     <p>
      当有新的服务进行注册或服务更新时，就会将数据发给Zookeeper
     </p>
     <p>
      Boostrap那边有一个Dubbo的客户端之类的东西，会受到Zookeeper变化的服务信息，实时进行更新
     </p>
     <p>
      当请求进行访问时，Soul网关直接调用Dubbo的客户端，让它去访问后台的Dubbo服务，拿到结果后返回即可
     </p>
     <h2 id="_5">
      总结
     </h2>
     <p>
      本篇对Soul-Client的Apache Dubbo模块进行探索，发现和HTTP的注册流程大致相同：
     </p>
     <ul>
      <li>
       1.获取对应的Bean（类）：
      </li>
      <li>
       HTTP是通过在每个Bean构造完成后进行操作，这样比Dubbo可能要费时
      </li>
      <li>
       <p>
        Dubbo在所有Bean构造完成后进行操作，直接能获取Dubbo相关的Bean
       </p>
      </li>
      <li>
       <p>
        2.注册判断：两者都是通过判断是否满足相应的注解
       </p>
      </li>
      <li>
       <p>
        3.注册信息：
       </p>
      </li>
      <li>
       HTTP没有中间层，所有必须要有额外的IP和端口信息
      </li>
      <li>
       Dubbo有Zookeeper中间层，Boostrap有个Dubbo客户端，通过Zookeeper能得到后台信息，就没有传入额外的IP和端口信息
      </li>
     </ul>
     <p>
      最后留一个疑问：为啥不能使用发射代理进行注册？
     </p>
     <h2 id="soul">
      Soul网关源码解析文章列表
     </h2>
     <h3 id="_6">
      掘金
     </h3>
     <h4 id="_7">
      了解与初步运行
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6917864624423436296">
        Soul网关源码解析（一） 概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917865804121767944">
        Soul网关源码解析（二）代码初步运行
       </a>
      </li>
     </ul>
     <h4 id="_8">
      请求处理流程解析
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6917866538712334343">
        Soul网关源码解析（三）请求处理概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6917867369909977102">
        Soul网关源码解析（四）Dubbo请求概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6918575905962983438">
        Soul网关源码解析（五）请求类型探索
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6918736260467015693">
        Soul网关源码解析（六）Sofa请求处理概览
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6919348164944232455/">
        Soul网关源码解析（七）限流插件初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6919774553241550855/">
        Soul网关源码解析（八）路由匹配初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920074307590684685/">
        Soul网关源码解析（九）插件配置加载初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920142348617777166">
        Soul网关源码解析（十）自定义简单插件编写
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920596034171174925">
        Soul网关源码解析（十一）请求处理小结
       </a>
      </li>
     </ul>
     <h4 id="_9">
      数据同步解析
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6920596173925384206">
        Soul网关源码解析（十二）数据同步初探
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920596028505178125">
        Soul网关源码解析（十三）Websocket同步数据-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920597298674302983">
        Soul网关源码解析（十四）HTTP数据同步-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6920764643967238151">
        Soul网关源码解析（十五）Zookeeper数据同步-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921170233868845064">
        Soul网关源码解析（十六）Nacos数据同步示例运行
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921325882753695757/">
        Soul网关源码解析（十七）Nacos数据同步解析-Bootstrap端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921495273122463751/">
        Soul网关源码解析（十八）Zookeeper数据同步初探-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921621915995996168/">
        Soul网关源码解析（十九）Nacos数据同步初始化修复-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6921988280187617287/">
        Soul网关源码解析（二十）Websocket数据同步-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6922301585288593416/">
        Soul网关源码解析（二十一）HTTP长轮询数据同步-Admin端
       </a>
      </li>
      <li>
       <a href="https://juejin.cn/post/6922584596810825735/">
        Soul网关源码解析（二十二）数据同步小结
       </a>
      </li>
     </ul>
     <h4 id="soul-client">
      Soul-Client模块
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6922643958455599111">
        Soul网关源码解析（二十三）SoulSpringMvcClient注解
       </a>
      </li>
     </ul>
     <h4 id="_10">
      番外
     </h4>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6918947689564471309">
        Soul网关源码阅读番外篇（一） HTTP参数请求错误
       </a>
      </li>
     </ul>
    </article>
   </div>
   <!-- Footer -->
   <footer id="footer">
    <p class="copyright">
     © Untitled. Design:
     <a href="https://html5up.net">
      HTML5 UP
     </a>
     .
    </p>
   </footer>
  </div>
  <!-- BG -->
  <div id="bg">
  </div>
  <!-- Scripts -->
  <script src="../assets/js/jquery.min.js">
  </script>
  <script src="../assets/js/browser.min.js">
  </script>
  <script src="../assets/js/breakpoints.min.js">
  </script>
  <script src="../assets/js/util.js">
  </script>
  <script src="../assets/js/main.js">
  </script>
 </body>
</html>
